#include <tchar.h>
#include "SApp.h"
#include "CViewD3D9.h"
#include "SImageManager.h"
#include "SSequencer.h"
#include "SConfig.h"
#include "SRendererDX9.h"
#include "types/types.h"

DEFINE_SINGLETON(SApp);

//----------------------------------------------
SApp::SApp() :
m_hInstance(NULL),
m_hWnd(NULL),
m_eState(E_SAVER)
{
	
}

//----------------------------------------------
bool SApp::install()
{
	return true;
}

//----------------------------------------------
void SApp::uninstall()
{
}

//----------------------------------------------
void SApp::init(HINSTANCE hInstance)
{
	// Singletons
	STimerManager::setInstance( new STimerManager );
	SConfig::setInstance( new SConfig );
	SImageManager::setInstance( new SImageManager );
	SSequencer::setInstance( new SSequencer );
	SRenderer::setInstance( new SRendererDX9 );

	m_hInstance = hInstance;
	SSequencer::instance()->loadFileList();

	initMonitors();

}

//----------------------------------------------
void SApp::release()
{
	// Singletons
	SConfig::destroy();
	SSequencer::destroy();
	SRenderer::destroy();
	STimerManager::destroy();
}

//----------------------------------------------
BOOL CALLBACK EnumMonitorCallback(HMONITOR,HDC,LPRECT rc,LPARAM)
{
	if (rc->left == 0 && rc->top == 0)
		SApp::instance()->m_oMonitorRects.insert(SApp::instance()->m_oMonitorRects.begin(),*rc);
	/*else
		g_pApp->m_oMonitorRects.push_back(*rc);*/

	return TRUE;
}

//----------------------------------------------
void SApp::initMonitors()
{
	int iNbMonitors = GetSystemMetrics(80); // 80=SM_CMONITORS

	// Multiple monitors
	if (iNbMonitors > 1)
	{
		typedef BOOL (CALLBACK *LUMONITORENUMPROC)(HMONITOR,HDC,LPRECT,LPARAM);
		typedef BOOL (WINAPI *LUENUMDISPLAYMONITORS)(HDC,LPCRECT,LUMONITORENUMPROC,LPARAM);
		HINSTANCE hUsrLib = LoadLibrary(_T("user32.dll"));
		LUENUMDISPLAYMONITORS pEnumDisplayMonitors = 0;
		if (hUsrLib!=NULL)
		{
			pEnumDisplayMonitors = (LUENUMDISPLAYMONITORS)GetProcAddress(hUsrLib, "EnumDisplayMonitors");
			if (pEnumDisplayMonitors!=NULL)
				(*pEnumDisplayMonitors)(NULL, NULL, EnumMonitorCallback, NULL);
			FreeLibrary(hUsrLib);
		}
	}

	// Default monitor
	if (m_oMonitorRects.size() == 0)
	{
		RECT rc;
		rc.left=0; rc.top=0; rc.right=GetSystemMetrics(SM_CXSCREEN); rc.bottom=GetSystemMetrics(SM_CYSCREEN);
		m_oMonitorRects.push_back(rc);
	}
}

//----------------------------------------------
void SApp::run()
{
	SSequencer::instance()->run();
	GetCursorPos(&m_oInitCursorPos);
	/*//InitTime=GetTickCount();
	for (int i=0; i<(int)m_oMonitorRects.size(); i++)
	{
		const RECT &oRect = m_oMonitorRects[i];
		DWORD exstyle = WS_EX_TOPMOST;
		
		CViewDesc oViewDesc;
		oViewDesc.id		= i;
		oViewDesc.x			= oRect.left;
		oViewDesc.y			= oRect.top;
		oViewDesc.width		= oRect.right - oRect.left;
		oViewDesc.height	= oRect.bottom - oRect.top;

		HWND hThis = CreateWindowEx(
			exstyle,
			_T("ScrClass"),
			_T(""),
			WS_POPUP|WS_VISIBLE,
			oViewDesc.x, oViewDesc.y, oViewDesc.width, oViewDesc.height,
			m_hWnd,
			NULL,
			m_hInstance,
			&oViewDesc);

		ShowWindow(hThis, 0);
		m_oViews[m_oViews.size()-1]->init();

		if (i == 0)
			m_hWnd = hThis;
	}*/

	UINT uiOldVal;

	if (m_eState == E_SAVER)
		SystemParametersInfo(SPI_SETSCREENSAVERRUNNING, 1, &uiOldVal, 0);

	MSG sMsg;


	for(;;)
	{
		while (PeekMessage(&sMsg, NULL, 0, 0, PM_REMOVE))
		{
			TranslateMessage(&sMsg);
			DispatchMessage(&sMsg);
		}

		if(sMsg.message == WM_QUIT)
			break;

		for (unsigned int i=0; i<m_oViews.size(); i++)
			m_oViews[i]->render();
	}

	if (m_eState == E_SAVER)
		SystemParametersInfo(SPI_SETSCREENSAVERRUNNING, 0, &uiOldVal, 0);
}

//----------------------------------------------
void SApp::addView(CView* pView)
{
	m_oViews.push_back(pView);
}

//----------------------------------------------
void SApp::processMessage(UINT uiMsg, int iId, WPARAM wParam, LPARAM lParam)
{
	/*//
	if (uiMsg == WM_TIMER) pView->OnTimer();
	else if (uiMsg == WM_PAINT) {PAINTSTRUCT ps; BeginPaint(hWnd,&ps); RECT rc; GetClientRect(hWnd,&rc); if (sav!=0) sav->OnPaint(ps.hdc,rc); EndPaint(hWnd,&ps);}
	else if (pView != 0) pView->OtherWndProc(uiMsg,wParam,lParam);
	//*/
	switch (uiMsg)
	{
	case WM_TIMER:
		{
			break;
		}
	case WM_PAINT :
		break;
	case WM_ACTIVATE: case WM_ACTIVATEAPP: case WM_NCACTIVATE:
		/*TCHAR pn[100]; GetClassName((HWND)lParam,pn,100); 
		bool ispeer = (_tcsncmp(pn,_T("ScrClass"),8)==0);
		if (ScrMode==smSaver && !IsDialogActive && LOWORD(wParam)==WA_INACTIVE && !ispeer && !SCRDEBUG)
		{ 
		Debug(_T("WM_ACTIVATE: about to inactive window, so sending close")); ReallyClose=true; PostMessage(hMain,WM_CLOSE,0,0); return 0;
		}*/
		{
			TCHAR pn[100];
			GetClassName((HWND)lParam, pn, 100); 
			bool bIsPeer = (_tcsncmp(pn,_T("ScrClass"),8)==0);
			if (!bIsPeer)
			{
				//exit(0);
				//PostMessage(m_hWnd, WM_CLOSE, 0, 0);
			}
		}
		break;
	case WM_SETCURSOR : 
		if (m_eState == E_SAVER)
			SetCursor(NULL);
		else
			SetCursor(LoadCursor(NULL, IDC_ARROW));
		break;
	case WM_LBUTTONDOWN : case WM_MBUTTONDOWN : case WM_RBUTTONDOWN : case WM_KEYDOWN :
		if (m_eState == E_SAVER)
		{
			ExitProcess(0);
			//exit(0);
			//PostMessage(m_hWnd, WM_CLOSE, 0, 0);
			return;
		}
		break;
	case WM_MOUSEMOVE :
		if (m_eState == E_SAVER)
		{
			POINT oPos;
			GetCursorPos(&oPos);
			int iDx = oPos.x - m_oInitCursorPos.x;
			int iDy = oPos.y - m_oInitCursorPos.y;
			if (abs(iDx) + abs(iDy) > 50)
			{
				ExitProcess(0);
				//exit(0);
				//PostMessage(m_hWnd, WM_CLOSE, 0, 0);
			}
		}
		break;
	case (WM_SYSCOMMAND):
		if (m_eState == E_SAVER)
		{
			if (wParam==SC_SCREENSAVE) return; // WM_SYSCOMMAND: gobbling up a SC_SCREENSAVE to stop a new saver from running.
			if (wParam==SC_CLOSE) return; // WM_SYSCOMMAND: gobbling up a SC_CLOSE
		}
		break;
	case WM_CLOSE :
		if (iId == 0)
		{
			SendMessage(m_hWnd, WM_SETCURSOR, 0, 0);
			GetCursorPos(&m_oInitCursorPos);
			DestroyWindow(m_hWnd);
		}
		break;
	case WM_DESTROY :
		//if (iId == 0 && m_eState == E_SAVER)
		ExitProcess(0);
		//exit(0);
			//PostQuitMessage(0);
		break;
	}
}